package proto;

import java.util.List;
import java.util.ArrayList;
import java.util.regex.*;

public class Composite extends BreadBoard implements BuildingBlock {

	
	private List<Output> outputs;
	private List<Input> inputs;
	private final String name;
	
	public String getName(){
		return this.name;
	}
	
	Composite(String filePath){
		super();
		
		Pattern p = Pattern.compile(".*\\w+\\.comp");
		Matcher m = p.matcher(filePath);
		if(m.matches()){
			String[] path = filePath.split("\\\\"); //Tördelés '\' karakterek mentén 1. ill 3. '\' escape a stringben 2. \ escape a patternben 4. \ a karakterami mentén tördelve lesz a sztring 
			path = path[path.length-1].split("\\."); //Tördelés pont mentén: 1. \ escape a stringben 2. \ escape a patternben (A pont bármilyen karakterre illeszkedik escape szekvencia nélkül)
			this.name = path[0]; // A név az elérísí útból származik => fájlnév .comp nélkül;
					
		} else{
			String[] path = filePath.split("\\\\");
			this.name = path[path.length-1];
		};
		
		outputs = new ArrayList<Output>();
		inputs = new ArrayList<Input>();
		
		this.loadComposite(filePath); //Felépül benne a BreadBoard
		
		
		//Csatlokozatlan Inputok, és minden Output kivezetése:
		
        for(BuildingBlock b : this.getBuildingBlocks()){
            
            if(b.getClass().equals(AndGate.class)){
                    Gate g = (AndGate) b;
                    for( Input i : g.getInputs()){
                            if(i.getConnectedOutput() == null){
                                    this.getInputs().add(i);
                            }
                    }
                    this.getOutputs().add(g.getOutput());
            }
            if(b.getClass().equals(OrGate.class)){
                    Gate g = (OrGate) b;
                    for( Input i : g.getInputs()){
                            if(i.getConnectedOutput() == null){
                                    this.getInputs().add(i);
                            }
                    }
                    this.getOutputs().add(g.getOutput());
            }
            if(b.getClass().equals(NotGate.class)){
                    Gate g = (NotGate) b;
                    for( Input i : g.getInputs()){
                            if(i.getConnectedOutput() == null){
                                    this.getInputs().add(i);
                            }
                    }
                    this.getOutputs().add(g.getOutput());
            }
            if(b.getClass().equals(LED.class)){
                    LED l = (LED) b;
                    if(l.getInput().getConnectedOutput() == null){
                            this.getInputs().add(l.getInput());
                    }
                    
            }
            if(b.getClass().equals(Oscilloscope.class)){
                    Oscilloscope o = (Oscilloscope) b;
                    if(o.getInput().getConnectedOutput() == null){
                            this.getInputs().add(o.getInput());
                    }
            }
            if(b.getClass().equals(Switch.class)){
                    Switch s = (Switch) b;
                    this.getOutputs().add(s.getOutput());
            }
            if(b.getClass().equals(SequenceGen.class)){
                    SequenceGen s = (SequenceGen) b;
                    this.getOutputs().add(s.getOutput());
            }
            if(b.getClass().equals(Composite.class)){
                    Composite c = (Composite) b;
                    for(Output out : c.getOutputs()){
                            this.getOutputs().add(out);
                    }
                    for(Input in : c.getInputs()){
                    	if(in.getConnectedOutput() == null){	
                            this.getInputs().add(in);
                    	}
                    }
            }            
        }//END for(buldigblocks)
        
        if(Main.verbose){
        	System.out.println("added block name: " + this.name + " type: COMPOSITE inputs: " + this.inputs.size() + " outputs: " + this.outputs.size());
        }
	}
	
	
	

	@Override
	public Boolean processSignal() {
		this.simulationRunning = true;
		
		ArrayList<Boolean> outValues = new ArrayList<Boolean>(this.outputs.size());
		
		for(Output o : this.outputs){
			
			outValues.add(o.getState());
		}
		
		Main.verbose= false;
		this.startSimulation(1);
		
		Main.verbose=true;
		
		for(int i = 1; i < this.outputs.size() ; i++){
			
			if(this.outputs.get(i).getState() != outValues.get(i)){
				if(Main.verbose){
					System.out.println("set block "+this.getName()+".out["+(i+1)+"] to: "+(this.outputs.get(i).getState() ?"1":"0"));
				}
			}
		}
		
		return false;
	}

	@Override
	public Boolean validate() {				
		for(Input in : inputs){			
			if (in.getConnectedOutput() == null)
				return false;			
		}
		
		return true;
	}

	
	List<Output> getOutputs(){
		
		return this.outputs;
	}

	List<Input> getInputs(){
		
		return this.inputs;
	}
}
